package me.jzn.alib.pref;

import android.content.Context;
import android.content.SharedPreferences;
import android.content.SharedPreferences.Editor;

import androidx.preference.PreferenceManager;

import java.io.File;
import java.util.Map;
import java.util.Set;

import me.jzn.alib.ALib;
import me.jzn.alib.utils.AndrPathUtil;
import me.jzn.core.exceptions.ShouldNotRunHereException;
import me.jzn.core.utils.Base64Util;

/**
 * Created by xqs on 2017/12/28.
 */

public class Pref {
    private static final String PREF_DEFAULT_NAME = "PREF_DEFAULT";
    // 系统默认的，用来存储settings
    private static Pref SYTEM;
    // 我们默认的，用来存储全局的变量
    private static Pref DEFAULT;
    //    private Editor editor;
    protected SharedPreferences mPref;
    private String mName;

    //=============================================
    private Pref() {
//        SharedPreferences
        this.mPref = PreferenceManager.getDefaultSharedPreferences(ALib.app());
    }

    public Pref(String name) {
        this(name, ALib.app().getSharedPreferences(name, Context.MODE_PRIVATE));
    }

    public Pref(String name, SharedPreferences prefImpl) {
        if (name == null || name.length() == 0) {
            throw new IllegalArgumentException("pref.name不能为空");
        }
        // 注意此时name仍然可能为空，因为有无参构造函数
        this.mName = name;
        this.mPref = prefImpl;
    }

    public static final Pref def() {
        if (DEFAULT == null) {
            //如果mPref也为空，他被clear了，但是没有通知
            DEFAULT = new Pref(PREF_DEFAULT_NAME);
        }
        return DEFAULT;
    }

    public static final Pref sys() {
        if (SYTEM == null) {
            SYTEM = new Pref();
        }
        return SYTEM;
    }

    public String getName() {
        return mName;
    }

    /**
     * 一般用于框架或者迁移
     */
    public Set<String> keys() {
        return mPref.getAll().keySet();
    }

    /**
     * 一般用于框架或者迁移
     */
    public Map<String, ?> getAll() {
        return mPref.getAll();
    }

    public boolean contains(String key) {
        return mPref.contains(key);
    }

    /**
     * 因为pref是异步的，因此只删除文件，可能导致没用
     */
    public void clear() {
        mPref.edit().clear().commit();
        if (PREF_DEFAULT_NAME.equals(mName)) {
            DEFAULT = null;
        } else if (mName == null) {
            SYTEM = null;
        }
        String prefName = (mName != null ? mName : ALib.app().getPackageName() + "_preferences");
        File prefFile = AndrPathUtil.getPrefFile(prefName);
        if (prefFile.exists()) {
            if (!prefFile.delete()) {
                prefFile.deleteOnExit();
            }
        }

        mPref = null;
        mName = null;
    }

    public void rename(String newName) {
        this.rename(newName, ALib.app().getSharedPreferences(newName, Context.MODE_PRIVATE));
    }

    protected final void rename(String newName, SharedPreferences newPref) {
        Editor newEditor = newPref.edit();
        for (Map.Entry<String, ?> entry : mPref.getAll().entrySet()) {
            String key = entry.getKey();
            Object value = entry.getValue();
            if (value instanceof Integer) {
                newEditor.putInt(key, (Integer) value);
            } else if (value instanceof Long) {
                newEditor.putLong(key, (Long) value);
            } else if (value instanceof Float) {
                newEditor.putFloat(key, (Float) value);
            } else if (value instanceof String) {
                newEditor.putString(key, (String) value);
            } else if (value instanceof Boolean) {
                newEditor.putBoolean(key, (Boolean) value);
            } else if (value instanceof Set) {
                newEditor.putStringSet(key, (Set<String>) value);
            } else {
                throw new ShouldNotRunHereException("未知的pref类型:" + value.getClass().getName());
            }
        }
        newEditor.apply();

        //旧的先commit再删除
        Editor oldEdit = mPref.edit();
        oldEdit.commit();
        File oldFile = AndrPathUtil.getPrefFile(mName);
        oldFile.delete();
        this.mPref = newPref;
        this.mName = newName;
    }

    /**
     * 用于一次性修改多个数据
     */
    public Editor edit() {
        return mPref.edit();
    }

    public static void putBytes(Editor editor, String key, byte[] bytes) {
        String base64 = Base64Util.encode(bytes, true);
        editor.putString(key, base64);
    }

    //=============================
    public void set(String... kvs) {
        Editor editor = mPref.edit();
        for (int i = 0; i < kvs.length; i = i + 2) {
            editor.putString(kvs[i], kvs[i + 1]);
        }
        editor.apply();
    }

    public void set(String key, boolean value) {
        Editor editor = mPref.edit();
        editor.putBoolean(key, value);
        editor.apply();
    }

    public void set(String key, byte[] value) {
        Editor editor = mPref.edit();
        putBytes(editor, key, value);
        editor.apply();
    }

    public void set(String key, int value) {
        Editor editor = mPref.edit();
        editor.putInt(key, value);
        editor.apply();
    }

    public void set(String key, float value) {
        Editor editor = mPref.edit();
        editor.putFloat(key, value);
        editor.apply();
    }

    public void set(String key, long value) {
        Editor editor = mPref.edit();
        editor.putLong(key, value);
        editor.apply();
    }

    public void set(String key, Set<String> value) {
        Editor editor = mPref.edit();
        editor.remove(key);
        //        editor.apply();//须先remove，否则无效
        editor.putStringSet(key, value);
        editor.apply();
    }

    public Set<String> getStringSet(String key) {
        return mPref.getStringSet(key, null);
    }

    public Set<String> getStringSet(String key, Set<String> defValue) {
        return mPref.getStringSet(key, defValue);
    }

    public String get(String key) {
        return mPref.getString(key, null);
    }

    public String get(String key, String defValue) {
        return mPref.getString(key, defValue);
    }

    public Boolean getBoolean(String key) {
        return mPref.getBoolean(key, false);
    }

    public boolean getBoolean(String key, boolean defValue) {
        return mPref.getBoolean(key, defValue);
    }

    public byte[] getBytes(String key) {
        String base64 = this.get(key);
        if (base64 == null) {
            return null;
        }
        return Base64Util.decode(base64);
    }


    public int getInt(String key) {
        return mPref.getInt(key, -1);
    }

    public int getInt(String key, int defValue) {
        return mPref.getInt(key, defValue);
    }

    public long getLong(String key) {
        return mPref.getLong(key, -1L);
    }

    public long getLong(String key, long defValue) {
        return mPref.getLong(key, defValue);
    }

    public float getFloat(String key) {
        return mPref.getFloat(key, -1F);
    }

    public float getFloat(String key, float defValue) {
        return mPref.getFloat(key, defValue);
    }

    public void remove(String key) {
        Editor editor = mPref.edit();
        editor.remove(key);
        editor.apply();
    }
}
